package org.devocean.groupbuying.dao.impl;

import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.devocean.groupbuying.dao.ProductDAO;
import org.devocean.groupbuying.domain.Article;
import org.devocean.groupbuying.domain.ArticlesLocalization;
import org.devocean.groupbuying.domain.Product;
import org.springframework.stereotype.Repository;

@Repository
public class ProductDAOImpl implements ProductDAO {

	@PersistenceContext
	private EntityManager em;

	private String slugify(String string) {
		return Normalizer.normalize(string.toLowerCase(), Form.NFD)
				.replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
				.replaceAll("[^\\p{Alnum}]+", "_");
	}

	public List<Product> findAllProducts() {
		return em.createQuery("select p from Product p ", Product.class)
				.getResultList();
	}

	public long countProducts() {
		return em
				.createQuery(
						"SELECT COUNT(p)  FROM Product p INNER JOIN   p.articlesLocalization al INNER JOIN  al.articles",
						Long.class).getSingleResult();
	}

	public List<Product> findProductsEntries(int firstResult, int maxResults) {

		Query query = em
				.createQuery(
						"select p from Product p "
								+ "INNER JOIN FETCH  p.articlesLocalization al ")
				.setFirstResult(firstResult).setMaxResults(maxResults);

		List<Product> products = query.getResultList();
		try {
			Set<Integer> idset = new HashSet<Integer>();
			for (Product product : products) {
				idset.add(product.getArticlesLocalization()
						.getArticlesLocalizationID());
			}
			try {
				List<ArticlesLocalization> articlesLocalizations = em
						.createQuery(
								"SELECT al FROM ArticlesLocalization al INNER JOIN FETCH al.articles a WHERE  al.articlesLocalizationID IN (:x)",
								ArticlesLocalization.class)
						.setParameter("x", idset).getResultList();

			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return products;

	}

	public Product findProductById(int id) {
		return em.find(Product.class, id);
	}

	public void removeProduct(int id) {
		final Product product = em.find(Product.class, id);

		if (product != null) {

			em.remove(product);
		}

	}

	public void linkToArticle(Product product) {
		for (Article article : product.getArticlesLocalization().getArticles()) {
			article.setArticlesLocalization(product.getArticlesLocalization());
		}
	}

	public Product saveProduct(Product product) {
		if (product.getArticlesLocalization().getArticlesLocalizationID() == null) {
			String title = product.getArticlesLocalization().getArticles()
					.iterator().next().getTitle();
			product.getArticlesLocalization().setPermalink(this.slugify(title));
		}
		linkToArticle(product);
		em.persist(product);
		return product;
	}

	public Product updateProduct(Product product) {
		linkToArticle(product);
		final Product merged = em.merge(product);
		return merged;
	}

	public Product findProductByArticleLocalization(int articleLocalizationID) {

		return em
				.createQuery(
						"SELECT p  FROM Product p where articlesLocalization.articlesLocalizationID=:al",
						Product.class)
				.setParameter("al", articleLocalizationID).getSingleResult();
	}

	public Product findProductByArticle(Integer articleID) {

		return em
				.createQuery(
						"SELECT p  FROM Product p INNER JOIN  p.articlesLocalization al INNER JOIN  al.articles a where a.articleID=:a",
						Product.class).setParameter("a", articleID)
				.getSingleResult();
	}

	public Product findProductByLang(Integer localizationKey,
			String localizationRequest) {

		try {
			Product product = em
					.createQuery(
							"select distinct p from Product p"
									+ " LEFT JOIN FETCH p.articlesLocalization al"
									+ " LEFT JOIN FETCH al.articles a"
									+ " where p.articlesLocalization.articlesLocalizationID=:localization and a.lang=:lang",
							Product.class)
					.setParameter("localization", localizationKey)
					.setParameter("lang", localizationRequest).getResultList()
					.get(0);
			return product;
		} catch (Exception e) {
			return null;
		}

	}

	public Product findProductById(String lang, int id) {
		try {
			Product product = em
					.createQuery(
							"select distinct p from Product p"
									+ "LEFT JOIN FETCH p.articlesLocalization al "
									+ "LEFT JOIN FETCH al.articles a "
									+ "INNER JOIN FETCH p.plans pl "
									+ "INNER JOIN FETCH pl.articlesLocalization pal"
									+ "INNER JOIN FETCH pal.articls pa"
									+ " WHERE p.productID=:pid AND a.lang=:lang",
							Product.class).setParameter("pid", id)
					.setParameter("lang", lang).getResultList().get(0);
			return product;
		} catch (Exception e) {
			return null;
		}
	}

}
